package org.flintparticles.twoD.renderers
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Stage;
	import flash.display3D.Context3DBlendFactor;
	import flash.display3D.Context3DProgramType;
	import flash.display3D.Context3DTextureFormat;
	import flash.display3D.Context3DVertexBufferFormat;
	import flash.display3D.IndexBuffer3D;
	import flash.display3D.Program3D;
	import flash.display3D.VertexBuffer3D;
	import flash.display3D.textures.Texture;
	import flash.events.Event;
	import flash.geom.Matrix3D;
	import flash.geom.Vector3D;
	
	import org.flintparticles.common.renderers.RendererBase;
	import org.flintparticles.common.stage3d.ShaderProgramManager;
	import org.flintparticles.common.stage3d.Stage3DManager;
	import org.flintparticles.common.stage3d.Vao;
	import org.flintparticles.common.stage3d.utils.Color;
	import org.flintparticles.common.stage3d.utils.Stage3DMath;
	import org.flintparticles.twoD.particles.Particle2D;
	import org.flintparticles.twoD.stage3d.images.GeomEntity2D;
	
	public class MegaRenderer extends RendererBase
	{
		
		[Embed(source="star1.jpg")]
		private var twirlBmp:Class;
		
		private var NUM_BUFFERS_MAX:uint = 3;///16
		private var NUM_PARTICLES:uint =4000;////16383
		
		private const SIZE:Number = 0.4;
		
		private var _sceneGraph:Vector.<GeomEntity2D>=new Vector.<GeomEntity2D>();
		private var _stageMath:Stage3DMath;
		private var _stage3Manager:Stage3DManager;
		private var _canRender:Boolean=false;
		private var _stage:Stage;
		private var _bgColor:uint=0xffffff;
		private var prog:Program3D;
		private var _vBufferXY:VertexBuffer3D;
		private var _vBufferRGB:VertexBuffer3D;
		//	private var _vBufferOffset:VertexBuffer3D;
		private var _indexBuffer:IndexBuffer3D;
		//
		private var _numBuffers:uint = 0;
		private var _start:uint;
		private var _positionAttrArray:Vector.<Vector.<Number>>;
		///	private var _velocityAttrArray:Vector.<Vector.<Number>>;
		public function MegaRenderer(stage:Stage,numOfParticles:uint=16383,numBuffers:uint=2,bgcolor:uint=0xffffff)
		{
			_stage=stage;
			_bgColor=bgcolor;
			NUM_PARTICLES=numOfParticles;
			_numBuffers=numBuffers;
			NUM_BUFFERS_MAX=_numBuffers;
			_stageMath=new Stage3DMath();
			_stageMath.setOrthographicProjection(_stage.stageWidth,_stage.stageHeight);
			initStage3DManager();
		}
		private function initStage3DManager():void{
			_stage3Manager=Stage3DManager.getInstance(_stage);
			_stage3Manager.addEventListener("CONTEXT3D_READY",onContextReady);
			_stage3Manager.setStage3dByIndex(0);
		}
		private function onContextReady(e:Event):void{
			prog=_stage3Manager.shaderProgramManager.getProgramByName(ShaderProgramManager.MASSIVE_PARTICLES_PROG);
			initVertexArrays();
			createBuffers();
			initTextureAttribute();
			initBuffers();
			setConstants();
			_stage3Manager.context3D.setProgram(prog);
			_canRender=true;
			
		}
		
		private function setConstants():void
		{
			// TODO Auto Generated method stub
			//	_stageMath.mProjectionMatrix=new Matrix3D();
			_stageMath.mProjectionMatrix.appendScale(4,4,1);
			_stageMath.mProjectionMatrix.appendTranslation(1, -1, 0);
		}
		
		private function createBuffers():void
		{
			
			var numVertices:uint = NUM_PARTICLES * 4;
			var numIndices:uint = NUM_PARTICLES * 6;
			_vBufferXY = _stage3Manager.context3D.createVertexBuffer(numVertices, 4);///2 by default without uv
			
			_vBufferRGB = _stage3Manager.context3D.createVertexBuffer(numVertices, 3);
			
			var cVec:Vector.<Number> = new Vector.<Number>(numVertices * 3);
			
			var r:Number;
			var g:Number;
			var b:Number;
			var index:uint = 0;
			for (var i:int = 0; i < NUM_PARTICLES; i++){
				
				r =i%3==0?Color.getRed(0xff0000)/ 255.0:Color.getRed(0xa10000)/ 255.0;///Math.sin(getTimer()/500);/// Color.getRed(Math.floor(Math.random()*0xffffff)) / 255.0;
				g =i%2==0?Color.getGreen(0x00ff00)/ 255.0:Color.getGreen(0x00a100)/ 255.0; ////Math.cos(getTimer()/500);//Color.getGreen(Math.floor(Math.random()*0xffffff)) / 255.0;
				b =i%1==0?Color.getBlue(0x0000ff)/ 255.0:Color.getBlue(0x0000a1)/ 255.0;////Math.sin(getTimer()/500); ///Color.getBlue(Math.floor(Math.random()*0xffffff)) / 255.0;
				
				
				
				cVec[index++] = r;
				cVec[index++] = g;
				cVec[index++] = b;
				cVec[index++] = r;
				cVec[index++] = g;
				cVec[index++] = b;
				cVec[index++] = r;
				cVec[index++] = g;
				cVec[index++] = b;
				cVec[index++] = r;
				cVec[index++] = g;
				cVec[index++] = b;
			}
			_vBufferRGB.uploadFromVector(cVec, 0, numVertices);
			_indexBuffer = _stage3Manager.context3D.createIndexBuffer(numIndices);
			
			var iVec:Vector.<uint> = new Vector.<uint>(numIndices);
			index = 0;
			var p:uint;
			for (i = 0; i < NUM_PARTICLES; i++){
				p = i << 2;
				iVec[index++] = p;
				iVec[index++] = p + 2;
				iVec[index++] = p + 1;
				iVec[index++] = p + 1;
				iVec[index++] = p + 2;
				iVec[index++] = p + 3;
			}
			_indexBuffer.uploadFromVector(iVec, 0, numIndices);
		}
		
		
		private var texture:Texture;
		private var screenTexture:Texture;
		private function initTextureAttribute():void{
			var btm:Bitmap=new twirlBmp();///new BitmapData(32,32);
			//bdata.perlinNoise(4,5,12,35435,true,true);
	   	texture=_stage3Manager.context3D.createTexture(32,32,Context3DTextureFormat.BGRA,false);
			texture.uploadFromBitmapData(btm.bitmapData);
			
		///	screenTexture= _stage3Manager.context3D.createTexture(512, 512, Context3DTextureFormat.BGRA, true);
		}
	
		private function initUVBuffer():void{
			
		}
		
		private function initVertexArrays():void
		{
			// TODO Auto Generated method stub
			var count:uint = 0;
			_positionAttrArray=new Vector.<Vector.<Number>>(NUM_BUFFERS_MAX);
			
			for (var j:int = 0; j < NUM_BUFFERS_MAX; j++){
				_positionAttrArray[j] = new Vector.<Number>(NUM_PARTICLES * 8*2);
				
				var index:uint = 0;
				for (var i:int = 0; i < NUM_PARTICLES; i++){
					var posX:Number = _stage.stageWidth * Math.random();
					var posY:Number = _stage.stageHeight * Math.random();
					_positionAttrArray[j][index++] = posX;
					_positionAttrArray[j][index++] = posY;
					_positionAttrArray[j][index++] =0;
					_positionAttrArray[j][index++] =0;
					_positionAttrArray[j][index++] = posX;
					_positionAttrArray[j][index++] = posY;
					_positionAttrArray[j][index++] = 1;
					_positionAttrArray[j][index++] = 0;
					_positionAttrArray[j][index++] = posX;
					_positionAttrArray[j][index++] = posY;
					_positionAttrArray[j][index++] = 0;
					_positionAttrArray[j][index++] = 1;
					_positionAttrArray[j][index++] = posX;
					_positionAttrArray[j][index++] = posY;
					_positionAttrArray[j][index++] = 1;
					_positionAttrArray[j][index++] = 1;
				
					
					
				
				}
				
			}
		}
		
		private function initBuffers():void{
		
			_stage3Manager.context3D.setVertexBufferAt(0, _vBufferXY, 0, Context3DVertexBufferFormat.FLOAT_2);
			_stage3Manager.context3D.setVertexBufferAt(1, _vBufferRGB, 0, Context3DVertexBufferFormat.FLOAT_3);
			_stage3Manager.context3D.setVertexBufferAt(2,  _vBufferXY,2, Context3DVertexBufferFormat.FLOAT_2);
			_stage3Manager.context3D.setTextureAt(1,texture);
			_stageMath.pushMatrix();
			
		}
		private var alpha:Number=1;
		//private var matr:Matrix3D=new Matrix3D();
		override protected function renderParticles(particles:Array):void{
			if(!_canRender)return;
			
			
			clear(_bgColor,1);
			
			//trace("Current particles length is -->"+particles.length);
			
			calcCPU(particles);
		//	_stageMath.mProjectionMatrix.invert();
		//	matr.appendRotation(alpha,Vector3D.Z_AXIS,new Vector3D(0,0,0));
			_stage3Manager.context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, _stageMath.mProjectionMatrix, true);
		//	_stage3Manager.context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 4,matr, true); 
			
		 
			
		//	var alphaVector:Vector.<Number> = new <Number>[alpha, alpha, alpha, alpha];
			//_stage3Manager.context3D.setBlendFactors(Context3DBlendFactor.SOURCE_ALPHA,Context3DBlendFactor.ONE);///add
			//	_stage3Manager.context3D.setBlendFactors(Context3DBlendFactor.DESTINATION_COLOR,Context3DBlendFactor.ZERO);///multiply
			///    _stage3Manager.context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, _stageMath.mModelViewMatrix, true); ///stageMath.mvpMatrix
		
			///setting alpha uniform
		//	_stage3Manager.context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, alphaVector, 1);
			
			_stage3Manager.context3D.setBlendFactors(Context3DBlendFactor.SOURCE_ALPHA,Context3DBlendFactor.ONE);
			for (var i:int = 0; i < _numBuffers; i++){
				_vBufferXY.uploadFromVector(_positionAttrArray[i], 0, NUM_PARTICLES * 4);
				
				
				
				_stage3Manager.context3D.drawTriangles(_indexBuffer);
				
			}
		//	_stage3Manager.context3D.setTextureAt(2, null);
			_stage3Manager.context3D.present();
			//_stageMath.resetMatrix();
			
			
		}
		
		private function calcCPU(particles:Array):void {
			//calculate each position
			var tmp:Number;
			
			var pos:Vector.<Number>;
			var vel:Vector.<Number>;
			var bufferCount:uint=0;
			
		
			for (var j:int = 0; j < _numBuffers; j++){
				var index:uint = 0;
				//	var index2:uint = 0;
				pos = _positionAttrArray[j];
				///,new Vector3D(tmp,tmp1,0)
				for (var i:int = 0; i < NUM_PARTICLES; i++){
					
					tmp =Particle2D(particles[i+bufferCount]).x;//// pos[index] + vel[index2];
					//// pos[index + 1] + vel[index2 + 1];	
				
					pos[index] = tmp+(-SIZE);///x
					pos[index + 4] = tmp+(-SIZE);///x
					pos[index + 8] = tmp+SIZE;//x
					pos[index + 12] = tmp+SIZE;//x
					
					tmp  =Particle2D(particles[i+bufferCount]).y;
					
					pos[index + 1] = tmp+(-SIZE);
					pos[index + 5] = tmp+SIZE;
					pos[index + 9] = tmp+(-SIZE);
					pos[index + 13] = tmp+SIZE;
					
					
					/*
					
					pos[index] = tmp+(-SIZE);///x
					pos[index + 4] = tmp+(-SIZE);///x
					pos[index + 8] = tmp+SIZE;//x
					pos[index + 12] = tmp+SIZE;//x
					
					
					tmp  =Particle2D(particles[i+bufferCount]).y//// pos[index + 1] + vel[index2 + 1];
					pos[index + 1] = tmp+(-SIZE);
					pos[index + 5] = tmp+SIZE;
					pos[index + 9] = tmp+(-SIZE);
					pos[index + 13] = tmp+SIZE;
					
					*/
					
					
					index += 16;
				}
				bufferCount+=(index/16);
			}
			
		}
		protected function renderParticle(particle:Particle2D):void{
			
		}
		public function clear(rgb:uint=0, alpha:Number=1.0):void
		{
			_stage3Manager.context3D.clear(
				Color.getRed(rgb)   / 255.0, 
				Color.getGreen(rgb) / 255.0, 
				Color.getBlue(rgb)  / 255.0,
				alpha);
			
		}
	}
}